package com.lse_api.control;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lse_api.config.log.ProjectLogConfig;
import com.lse_api.entity.*;
import com.lse_api.service.*;
import com.lse_api.utils.PageUtil;
import com.lse_api.utils.ReturnMsg;
import com.lse_api.utils.Status;
import com.lse_api.utils.UUID;
import com.lse_api.utils.pdfutil.PDFUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import org.springframework.stereotype.Controller;
import com.lse_api.exception.LseException;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 项目 前端控制器
 * </p>
 *
 * @author 祁雪
 * @since 2020-05-11
 */
@Slf4j
@Controller
@RequestMapping("/lseapi/api/project")
public class ProjectController extends LseException implements ReturnMsg {

    @Autowired
    private ProjectService projectService;

    @Autowired
    private ProjectApiService projectApiService;

    @Autowired
    private ProjectApiParpamService projectApiParpamService;

    @Autowired
    private GroupProjectService groupProjectService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private HttpServletRequest request;

    @Value("${com.lse.pdf.template}")
    public String pdfTemplate;

    @Value("${com.lse.project.pdf.save}")
    public String projectSavePath;

    @Value("${com.lse.project.pdf.saveFolder}")
    public String projectSave;

    @Value("${com.lse.api.pdf.save}")
    public String apiSavePath;

    @Value("${com.lse.api.pdf.saveFolder}")
    public String apiSave;

    /**
     * 创建项目
     *
     * @param project
     * @return
     */
    @RequestMapping(value = "/createProject")
    @ResponseBody
    public Status createProject(Project project) {
        Token token = (Token) request.getAttribute("token");

        if (StringUtils.isEmpty(project.getProjectName())) {
            return Status.error(API_PROJECT_NAME);
        }

        project.setCreateTime(new Date());
        project.setProjectCreate(token.getUsersUid());

        boolean flag = projectService.save(project);

        if (flag) {
            ProjectLogConfig.saveProjectLog("创建项目, 项目名称: " + project.getProjectName(), project.getId());
        }

        return flag ? Status.success(CREATE_SUCCESS) : Status.error(CREATE_FAILURE);
    }

    /**
     * 删除项目
     * 检查项目创建者是否是已登录用户
     * project: 项目id
     *
     * @return
     */
    @RequestMapping(value = "/deleteProject")
    @ResponseBody
    public Status deleteProject() {

        String projectId = request.getParameter("project");

        Token token = (Token) request.getAttribute("token");

        QueryWrapper<Project> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", projectId);
        queryWrapper.eq("project_create", token.getUsersUid());

        Project project = projectService.getOne(queryWrapper);

        if (project == null) {
            return Status.error(API_PROJECT_NOT_ME);
        }

        // 清除此项目内全部数据
        // 清除项目日志
        ProjectLogConfig.emptyProjectLog(project.getId());
        // 清除项目内api参数
        Map<String, Object> map = new HashMap<>();
        map.put("project_id", project.getId());
        projectApiParpamService.removeByMap(map);
        // 清除项目内api
        projectApiService.removeByMap(map);
        // 清除项目组绑定
        groupProjectService.removeByMap(map);
        // 清除项目本体
        boolean flag = projectService.remove(queryWrapper);

        return flag ? Status.success(DELETESUCCESS) : Status.error(DELETEFAILURE);
    }

    /**
     * 创建api
     *
     * @param projectApi
     * @return
     */
    @RequestMapping(value = "/createApi", method = RequestMethod.POST)
    @ResponseBody
    public Status createApi(ProjectApi projectApi) {

        if (StringUtils.isEmpty(projectApi.getProjectId())) {
            return Status.error(API_PROJECT_ID);
        }

        if (StringUtils.isEmpty(projectApi.getName())) {
            return Status.error(API_PROJECT_API_NAME);
        }

        if (StringUtils.isEmpty(projectApi.getUrl())) {
            return Status.error(API_PROJECT_API_URL);
        }

        Token token = (Token) request.getAttribute("token");

        projectApi.setApiCreate(token.getUsersUid());
        projectApi.setCreateTime(new Date());

        boolean flag = projectApiService.save(projectApi);

        if (flag) {
            ProjectLogConfig.saveProjectLog("创建项目API, API名称: " + projectApi.getName(), projectApi.getProjectId());
            if (projectApi.getParams() != null && projectApi.getParams().size() > 0) {
                projectApi.setParams(projectApi.getParams().stream().filter(projectApiParpam -> !StringUtils.isEmpty(projectApiParpam.getParamName())).collect(Collectors.toList()));
                projectApi.getParams().forEach(projectApiParpam -> {
                    projectApiParpam.setId(UUID.getUUIDToStr());
                    projectApiParpam.setApiId(projectApi.getId());
                    projectApiParpam.setCreateTime(new Date());
                    projectApiParpam.setProjectId(projectApi.getProjectId());
                });

                projectApiParpamService.saveBatch(projectApi.getParams());

            }
        }

        return flag ? Status.success(CREATE_SUCCESS) : Status.error(CREATE_FAILURE);
    }

    /**
     * 修改api
     *
     * @param projectApi
     * @return
     */
    @RequestMapping(value = "/updateProjectApi")
    @ResponseBody
    public Status updateProjectApi(ProjectApi projectApi) {

        if (StringUtils.isEmpty(projectApi.getId())) {
            return Status.error(API_PROJECT_API_ID);
        }

        if (StringUtils.isEmpty(projectApi.getProjectId())) {
            return Status.error(API_PROJECT_ID);
        }

        if (StringUtils.isEmpty(projectApi.getName())) {
            return Status.error(API_PROJECT_API_NAME);
        }

        if (StringUtils.isEmpty(projectApi.getUrl())) {
            return Status.error(API_PROJECT_API_URL);
        }

        Token token = (Token) request.getAttribute("token");

        // 重置参数
        projectApi.setApiCreate(null);
        projectApi.setCreateTime(null);
        projectApi.setApiUpdate(token.getUsersUid());
        projectApi.setUpdateTime(new Date());

        // 读取此API
        ProjectApi projectApiCheck = projectApiService.getById(projectApi.getId());

        if (projectApiCheck == null) {
            return Status.error(API_PROJECT_API_NULL);
        }

        // 检查权限
        boolean check = checkApi(projectApiCheck);
        if (!check) {
            check = checkProject(projectApi.getProjectId().toString());
        }
        if (!check) {
            return Status.error(API_PROJECT_API_NOT_ME);
        }

        boolean flag = projectApiService.updateById(projectApi);

        if (flag) {
            ProjectLogConfig.saveProjectLog("更新了原名称为: " + projectApiCheck.getName() + "的API, 现名称: " + projectApi.getName(), projectApi.getProjectId());
        }

        return flag ? Status.success(UPDATESUCCESS) : Status.error(UPDATEFAILURE);
    }

    /**
     * 删除此api
     * api: api接口ID
     *
     * @return
     */
    @RequestMapping(value = "/deleteProjectApi")
    @ResponseBody
    public Status deleteProjectApi() {
        String projectApiId = request.getParameter("api");

        // 读取此API
        ProjectApi projectApi = projectApiService.getById(projectApiId);

        if (projectApi == null) {
            return Status.error(API_PROJECT_API_NULL);
        }

        // 检查权限
        boolean check = checkApi(projectApi);
        if (!check) {
            check = checkProject(projectApi.getProjectId().toString());
        }
        if (!check) {
            return Status.error(API_PROJECT_API_NOT_ME);
        }

        // 删除参数列表
        Map<String, Object> map = new HashMap<>();
        map.put("api_id", projectApi.getId());
        map.put("project_id", projectApi.getProjectId());
        projectApiParpamService.removeByMap(map);

        boolean flag = projectApiService.removeById(projectApi.getId());

        if (flag) {
            ProjectLogConfig.saveProjectLog("删除了项目API API名称为: " + projectApi.getName(), projectApi.getProjectId());
        }

        return flag ? Status.success(DELETESUCCESS) : Status.error(DELETEFAILURE);
    }

    /**
     * 添加api参数
     *
     * @param projectApiParpam
     * @return
     */
    @RequestMapping(value = "/addApiParam")
    @ResponseBody
    public Status addApiParam(ProjectApiParpam projectApiParpam) {
        if (StringUtils.isEmpty(projectApiParpam.getApiId())) {
            return Status.error(API_PROJECT_API_ID);
        }

        if (StringUtils.isEmpty(projectApiParpam.getProjectId())) {
            return Status.error(API_PROJECT_ID);
        }

        if (StringUtils.isEmpty(projectApiParpam.getParamName())) {
            return Status.error(API_PROJECT_API_PARAM_NAME);
        }
        projectApiParpam.setCreateTime(new Date());
        projectApiParpam.setId(UUID.getUUIDToStr());

        // 检查api是否存在
        ProjectApi projectApi = projectApiService.getById(projectApiParpam.getApiId());

        if (projectApi == null) {
            return Status.error(API_PROJECT_API_NULL);
        }

        boolean flag = projectApiParpamService.save(projectApiParpam);

        if (flag) {
            ProjectLogConfig.saveProjectLog("新增API参数: " + projectApiParpam.getParamName(), projectApiParpam.getProjectId());
        }

        return flag ? Status.success(SAVESUCCESS) : Status.error(SAVEFAILURE);

    }

    /**
     * 删除api参数
     * param: API参数ID
     *
     * @return
     */
    @RequestMapping(value = "/deleteApiParam")
    @ResponseBody
    public Status deleteApiParam() {
        String param = request.getParameter("param");

        if (StringUtils.isEmpty(param)) {
            return Status.error(API_PROJECT_API_PARAM_ID);
        }

        ProjectApiParpam projectApiParpam = projectApiParpamService.getById(param);

        if (projectApiParpam == null) {
            return Status.error(API_PROJECT_API_PARAM_NULL);
        }

        // 检查权限
        boolean check = checkApi(projectApiParpam.getApiId().toString());
        if (!check) {
            check = checkProject(projectApiParpam.getProjectId().toString());
        }
        if (!check) {
            return Status.error(API_PROJECT_API_NOT_ME);
        }

        boolean flag = projectApiParpamService.removeById(projectApiParpam.getId());

        if (flag) {
            ProjectLogConfig.saveProjectLog("删除了API参数: " + projectApiParpam.getParamName(), projectApiParpam.getProjectId());
        }

        return flag ? Status.success(DELETESUCCESS) : Status.error(DELETEFAILURE);

    }

    /**
     * 修改api参数
     *
     * @return
     */
    @RequestMapping(value = "/updateApiParam")
    @ResponseBody
    public Status updateApiParam(ProjectApiParpam projectApiParpam) {

        if (StringUtils.isEmpty(projectApiParpam.getId())) {
            return Status.error(API_PROJECT_API_PARAM_ID);
        }

        if (StringUtils.isEmpty(projectApiParpam.getParamName())) {
            return Status.error(API_PROJECT_API_PARAM_NAME);
        }


        ProjectApiParpam projectApiParpamCheck = projectApiParpamService.getById(projectApiParpam.getId());

        if (projectApiParpamCheck == null) {
            return Status.error(API_PROJECT_API_PARAM_NULL);
        }

        // 检查权限
        boolean check = checkApi(projectApiParpamCheck.getApiId().toString());
        if (!check) {
            check = checkProject(projectApiParpamCheck.getProjectId().toString());
        }
        if (!check) {
            return Status.error(API_PROJECT_API_NOT_ME);
        }

        boolean flag = projectApiParpamService.updateById(projectApiParpam);

        if (flag) {
            ProjectLogConfig.saveProjectLog("更新了API参数, 原名称: " +
                            projectApiParpamCheck.getParamName() + ", 现名称: " +
                            projectApiParpam.getParamName(),
                    projectApiParpam.getProjectId());
        }

        return flag ? Status.success(UPDATESUCCESS) : Status.error(UPDATEFAILURE);
    }

    /**
     * 读取已登录用户的项目列表
     * pageNo: 页码
     * pageSize: 每页数量
     *
     * @return
     */
    @RequestMapping(value = "/getProjectList")
    @ResponseBody
    public Status getProjectList() {

        Token token = (Token) request.getAttribute("token");

        String pageNo = request.getParameter("pageNo");

        String pageSize = request.getParameter("pageSize");

        Map<String, Integer> map = PageUtil.getPage(pageNo, pageSize);

        QueryWrapper<Project> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("project_create", token.getUsersUid())
                .orderByDesc("create_time");

        PageHelper.startPage(map.get("pageNo"), map.get("pageSize"));

        List<Project> list = projectService.list(queryWrapper);

        PageInfo<Project> pageInfo = new PageInfo<>(list);

        return Status.success(pageInfo);
    }

    /**
     * 查询项目下api接口列表
     * api参数需要进入详情才可读取
     * project: 项目ID
     * pageNo: 页码
     * pageSize: 每页数量
     *
     * @return
     */
    @RequestMapping(value = "/getProjectApiList")
    @ResponseBody
    public Status getProjectApiList() {

        String projectId = request.getParameter("project");

        if (StringUtils.isEmpty(projectId)) {
            return Status.error(API_PROJECT_ID);
        }

        String pageNo = request.getParameter("pageNo");

        String pageSize = request.getParameter("pageSize");

        Map<String, Integer> map = PageUtil.getPage(pageNo, pageSize);

        PageHelper.startPage(map.get("pageNo"), map.get("pageSize"));

        List<ProjectApi> list = projectApiService.getApiListByProject(projectId);

        PageInfo<ProjectApi> pageInfo = new PageInfo<>(list);

        return Status.success(pageInfo);

    }

    /**
     * 读取api参数列表
     * project: 项目ID
     * api: 接口api ID
     *
     * @return
     */
    @RequestMapping(value = "/getProjectApiParamList")
    @ResponseBody
    public Status getProjectApiParamList() {

        String projectId = request.getParameter("project");

        String apiId = request.getParameter("api");

        if (StringUtils.isEmpty(projectId)) {
            return Status.error(API_PROJECT_ID);
        }

        if (StringUtils.isEmpty(apiId)) {
            return Status.error(API_PROJECT_API_ID);
        }

        QueryWrapper<ProjectApiParpam> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("api_id", apiId)
                .eq("project_id", projectId);

        List<ProjectApiParpam> list = projectApiParpamService.list(queryWrapper);

        return Status.success(list);
    }

    /**
     * 生成项目接口PDF文档
     * project: 项目ID
     *
     * @return
     */
    @RequestMapping(value = "/getProjectPdf")
    @ResponseBody
    public Status getProjectPdf() {

        String projectId = request.getParameter("project");

        if (StringUtils.isEmpty(projectId)) {
            return Status.error(API_PROJECT_ID);
        }

        // 读取项目
        Project project = projectService.getById(projectId);

        if (project == null) {
            return Status.error(API_PROJECT_NULL);
        }

        // 读取项目创建者
        QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("users_uid", project.getProjectCreate());

        UserInfo userInfo = userInfoService.getOne(userInfoQueryWrapper);

        // 读取项目旗下api接口列表
        List<ProjectApi> projectApis = projectApiService.getApiListByProject(project.getId().toString());

        // 循环读取api旗下参数列表
        projectApis.forEach(projectApi -> {
            QueryWrapper<ProjectApiParpam> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("api_id", projectApi.getId())
                    .eq("project_id", projectApi.getProjectId());

            projectApi.setParams(projectApiParpamService.list(queryWrapper));
        });

        Map<String, Object> data = new HashMap<>();
        data.put("project", project);
        data.put("projectCreate", userInfo);
        data.put("apis", projectApis);


        // 创建ftl config
        try {

            PDFUtil.getFreemarkerConfig(pdfTemplate);

            String outPutPath = projectSavePath + File.separator + project.getId() + ".pdf";

            File file = new File(outPutPath);
            file.getParentFile().mkdirs();

            PDFUtil.generateToFile(pdfTemplate,
                    "project_pdf.ftl", null, data,
                    outPutPath);

            if (file.exists()) {
                String src = "http://" + request.getServerName() + ":" + request.getServerPort() + "/" +
                        request.getContextPath() + "/" + projectSave + "/" + project.getId() + ".pdf";

                return Status.success("pdf create success", src);

            }

        } catch (Exception e) {
            log.error("create pdf out error", e);
        }

        return Status.error(PDF_CREATE_ERROR);

    }

    /**
     * 根据api id数组 导出此项目选择的api
     * project: 项目ID
     * select[]: 已选择的api id数组
     *
     * @return
     */
    @RequestMapping(value = "/getProjectPdfBySelect")
    @ResponseBody
    public Status getProjectPdfBySelect() {

        String projectId = request.getParameter("project");

        String[] ids = request.getParameterValues("select[]");

        if (StringUtils.isEmpty(projectId)) {
            return Status.error(API_PROJECT_ID);
        }

        if (ids == null || ids.length == 0) {
            return Status.error(API_PROJECT_API_ID);
        }

        // 读取项目
        Project project = projectService.getById(projectId);

        if (project == null) {
            return Status.error(API_PROJECT_NULL);
        }

        // 读取项目创建者
        QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("users_uid", project.getProjectCreate());

        UserInfo userInfo = userInfoService.getOne(userInfoQueryWrapper);

        // 读取项目旗下api接口列表
        List<ProjectApi> projectApis = projectApiService.getApiListByProjectBySelect(project.getId().toString(),
                Arrays.asList(ids));

        // 循环读取api旗下参数列表
        projectApis.forEach(projectApi -> {
            QueryWrapper<ProjectApiParpam> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("api_id", projectApi.getId())
                    .eq("project_id", projectApi.getProjectId());

            projectApi.setParams(projectApiParpamService.list(queryWrapper));
        });

        Map<String, Object> data = new HashMap<>();
        data.put("project", project);
        data.put("projectCreate", userInfo);
        data.put("apis", projectApis);


        // 创建ftl config
        try {

            PDFUtil.getFreemarkerConfig(pdfTemplate);

            String outPutPath = projectSavePath + File.separator + project.getId() + ".pdf";

            File file = new File(outPutPath);
            file.getParentFile().mkdirs();

            PDFUtil.generateToFile(pdfTemplate,
                    "project_pdf.ftl", null, data,
                    outPutPath);

            if (file.exists()) {
                String src = "http://" + request.getServerName() + ":" + request.getServerPort() + "/" +
                        request.getContextPath() + "/" + projectSave + "/" + project.getId() + ".pdf";

                return Status.success("pdf create success", src);

            }

        } catch (Exception e) {
            log.error("create pdf out error", e);
        }

        return Status.error(PDF_CREATE_ERROR);

    }

    /**
     * 项目权限验证 检查项目是否由登录者创建
     *
     * @param projectId
     * @return
     */
    public boolean checkProject(String projectId) {

        Token token = (Token) request.getAttribute("token");

        Project project = projectService.getById(projectId);

        if (project == null) {
            return false;
        }

        return project.getProjectCreate().equalsIgnoreCase(token.getUsersUid());
    }

    /**
     * 项目权限验证 检查项目是否由登录者创建
     *
     * @param project
     * @return
     */
    public boolean checkProject(Project project) {

        if (project == null) {
            return false;
        }

        Token token = (Token) request.getAttribute("token");

        return project.getProjectCreate().equalsIgnoreCase(token.getUsersUid());
    }

    /**
     * api权限验证 检查api是否由登录者创建
     *
     * @param apiId
     * @return
     */
    public boolean checkApi(String apiId) {

        Token token = (Token) request.getAttribute("token");

        ProjectApi projectApi = projectApiService.getById(apiId);

        if (projectApi == null) {
            return false;
        }

        return projectApi.getApiCreate().equalsIgnoreCase(token.getUsersUid());
    }

    /**
     * api权限验证 检查api是否由登录者创建
     *
     * @param projectApi
     * @return
     */
    public boolean checkApi(ProjectApi projectApi) {

        if (projectApi == null) {
            return false;
        }

        Token token = (Token) request.getAttribute("token");

        return projectApi.getApiCreate().equalsIgnoreCase(token.getUsersUid());
    }

}

